import { CharStreams, CommonTokenStream } from 'antlr4ts';
import { PieLexer } from './PieLexer';

import { AddexprContext, AddExprContext, AssignStatementContext, AtomContext, CallContext, CallStatementContext, EmptyStatementContext, EqExprContext, ExprContext, FieldVarContext, FunctionDefinitionContext, IfStatementContext, InstanceContext, LtExprContext, MulexprContext, PieParser, PrintStatementContext, ProgramContext, QidContext, ReturnStatementContext, SimpleVarContext, SlistContext, StatementContext, StructDefinitionContext, StructDefStatementContext, SubExprContext, VardefContext, WhileStatementContext, } from './PieParser';

// 0 代码
let code = `
print f(4)           # references definition on next line
def f(x) return 2*x
print new User       # references definition on next line
struct User { name, password }
`;

// 1 解析得到语法树
let inputStream = CharStreams.fromString(code);
let lexer = new PieLexer(inputStream);
let tokenStream = new CommonTokenStream(lexer);
let parser = new PieParser(tokenStream);
let tree = parser.program();

// 2 符号的解析
import { FunctionSymbol, Scope, StructSymbol, SymbolTable, VariableSymbol, _Symbol } from './PieSymbol';

import { ParseTreeWalker } from 'antlr4ts/tree/ParseTreeWalker'
import { PieListener } from './PieListener';
import { ParseTreeListener } from "antlr4ts/tree/ParseTreeListener";

class DefListener implements PieListener {
    symTab: SymbolTable;
    currentScope: Scope | null;

    constructor() {
        this.symTab = new SymbolTable();
        this.currentScope = this.symTab.globals
    }
    // 变量的声明
    enterAssignStatement(ctx: AssignStatementContext) {
        // 变量名称
        let id = ctx.qid().text;
        // 判断类型 int float char string 求值阶段
        let varSymbol = new VariableSymbol(
            id
        );
        // 添加变量到当前作用域
        this.currentScope?.define(varSymbol)

    }
    // 结构体的定义
    enterStructDefinition(ctx: StructDefinitionContext) {
        let structDef = new StructSymbol(
            ctx.ID().text,
            this.currentScope as Scope
        );
        this.currentScope?.define(structDef);
        // 切换结构体作用域
        this.currentScope = structDef;
    }
    exitStructDefinition(ctx: StructDefinitionContext) {
        // 切换上级作用域
        this.currentScope = (this.currentScope as Scope).getEnclosingScope();
    }
    // 结构体成员 // 函数的参数
    enterVardef(ctx: VardefContext) {
        // 添加结构体内部变量
        this.currentScope?.define(
            new VariableSymbol(
                ctx.ID().text
            )
        )
    }

    // 函数的定义
    enterFunctionDefinition(ctx: FunctionDefinitionContext) {
        let functionDef = new FunctionSymbol(
            ctx.ID().text,
            null,
            this.currentScope as Scope
        );
        // 函数的语句列表
        functionDef.slist = ctx.slist();

        this.currentScope?.define(functionDef);
        this.currentScope = functionDef;
    }
    // 参数记录 enterVarDef

    exitFunctionDefinition(ctx: FunctionDefinitionContext) {
        this.currentScope = (this.currentScope as Scope).getEnclosingScope();
    }
}

const listener = new DefListener();
ParseTreeWalker.DEFAULT.walk(listener as ParseTreeListener, tree)
console.log(listener.symTab.toString())

// 3 程序的求值
import { AbstractParseTreeVisitor } from 'antlr4ts/tree/AbstractParseTreeVisitor'
import { PieVisitor } from './PieVisitor';

function isNumber(val: any) {
    if (parseFloat(val).toString() == "NaN") {
        return false;
    } else {
        return true;
    }
}


class EvalVisitor extends AbstractParseTreeVisitor<boolean | number | string> implements PieVisitor<boolean | number | string>{
    // 声明符号表
    symTab: SymbolTable;
    currentScope: Scope | null;
    funcStack: FunctionSymbol[] = [];

    result: number | string = 0;

    constructor(symTab: SymbolTable) {
        super();
        this.symTab = symTab;
        this.currentScope = this.symTab.globals;
        // 注册基础函数
    }
    protected defaultResult(): boolean | number | string {
        return this.result;
    }

    /**
     * Visit a parse tree produced by the `addExpr`
     * labeled alternative in `PieParser.addexpr`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitAddExpr(ctx: AddExprContext) {
        let childExpr = ctx.mulexpr();
        if (childExpr.length == 1) {
            // 单个表达式
            let leftValue = this.visitMulexpr(childExpr[0]);
            return leftValue;
        } else if (childExpr.length > 1) {
            let result = 0;
            childExpr.forEach(c => {
                let tempV = this.visitMulexpr(c);
                if (isNumber(tempV)) {
                    result = result + (tempV as number)
                } else {
                    console.log("add", tempV)
                    throw new Error("add error")
                }
            })
            return result;
        }
        return -1
    }

    /**
     * Visit a parse tree produced by the `subExpr`
     * labeled alternative in `PieParser.addexpr`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitSubExpr(ctx: SubExprContext) {
        let childExpr = ctx.mulexpr();
        if (childExpr.length == 1) {
            // 单个表达式 任意值
            let leftValue = this.visitMulexpr(childExpr[0]);
            return leftValue;
        } else if (childExpr.length > 1) {
            let result = 0;
            // 最左边
            let leftExpr = childExpr[0];
            let leftValue = this.visitMulexpr(leftExpr);

            if (isNumber(leftValue)) {
                result = leftValue as number;
            } else {
                console.log("sub", leftValue)
                throw new Error("sub error")
            }

            childExpr.forEach(c => {
                let tempV = this.visitMulexpr(c);
                if (isNumber(tempV)) {
                    result = result - (tempV as number)
                } else {
                    console.log("sub", tempV)
                    throw new Error("sub error")
                }
            })
            return result;

        }
        return -1
    }

    /**
     * Visit a parse tree produced by the `simpleVar`
     * labeled alternative in `PieParser.qid`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitSimpleVar(ctx: SimpleVarContext) {
        // 读取变量值
        let varDef = this.currentScope?.resolve(ctx.ID().text)
        if (varDef == null) {
            console.log("simpleVar Error", ctx.ID().text)
            throw new Error("simpleVar error")
        }
        return (varDef as VariableSymbol).value
    }

    /**
     * Visit a parse tree produced by the `fieldVar`
     * labeled alternative in `PieParser.qid`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitFieldVar(ctx: FieldVarContext) {
        // 读取结构体的值
        let fieldIds = ctx.ID();
        let tempScope = this.currentScope;
        let result: any = null;

        fieldIds.forEach((f, i) => {
            let tempField = null;
            if (i == 0) {
                tempField = tempScope?.resolve(f.text);
            } else {
                tempField = (tempScope as StructSymbol).findField(f.text);
            }

            if (tempField == null) {
                console.log("fieldVar Error", f)
                throw new Error("fieldVar error")
            } else {
                // 最后的一个
                if (i == fieldIds.length - 1) {
                    result = (tempField as VariableSymbol).value
                } else {
                    (tempScope as Scope) = (tempField as StructSymbol)
                }
            }
        })
        return result
    }

    /**
     * Visit a parse tree produced by the `structDefStatement`
     * labeled alternative in `PieParser.statement`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitStructDefStatement(ctx: StructDefStatementContext) {
        // 求值器不处理
        return 0
    }

    /**
     * Visit a parse tree produced by the `assignStatement`
     * labeled alternative in `PieParser.statement`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitAssignStatement(ctx: AssignStatementContext) {
        let qid = ctx.qid();

        let expr = ctx.expr();
        let exprValue = this.visitExpr(expr);

        // simpleVar还是fieldvar
        if (qid instanceof SimpleVarContext) {
            let varName = qid.ID().text;
            // 查找符号表
            let varDef = this.currentScope?.resolve(varName);
            if (varDef == null) {
                console.log(`${varName} = ${expr}`)
                throw new Error("assign error")
            }
            // 赋值
            (varDef as VariableSymbol).value = exprValue;
        } else if (qid instanceof FieldVarContext) {
            // 结构体 a.b.c
            let structFileds = qid.ID();
            // 结构体堆栈
            let tempScope = this.currentScope;

            for (let i = 0; i < structFileds.length; i++) {
                // 读取 
                let tempStruct = structFileds[i].text;
                let def = null;
                if (i == 0) {
                    def = tempScope?.resolve(tempStruct);
                } else {
                    def = (tempScope as StructSymbol)?.findField(tempStruct);
                }
                if (def == null) {
                    console.log("structFileds", structFileds.toString());
                    throw new Error("struct def error")
                } else {
                    //检查是否到底最后
                    if (i == structFileds.length - 1) {
                        (def as VariableSymbol).value = exprValue
                    } else {
                        (tempScope as Scope) = def as StructSymbol;
                    }
                }
            }
        }
        return 0
    }

    /**
     * Visit a parse tree produced by the `returnStatement`
     * labeled alternative in `PieParser.statement`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitReturnStatement(ctx: ReturnStatementContext) {
        let exprValue = this.visitExpr(ctx.expr());
        // 函数栈弹出 
        let currentFunc = this.funcStack.pop();
        this.currentScope = currentFunc?.getEnclosingScope() as Scope;
        return exprValue;
    }

    /**
     * Visit a parse tree produced by the `printStatement`
     * labeled alternative in `PieParser.statement`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitPrintStatement(ctx: PrintStatementContext) {
        let exprValue = this.visitExpr(ctx.expr());
        console.log("ok",exprValue);
        return 0
    }

    /**
     * Visit a parse tree produced by the `ifStatement`
     * labeled alternative in `PieParser.statement`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitIfStatement(ctx: IfStatementContext) {
        let condExprValue = this.visitExpr(ctx.expr());
        let slists = ctx.slist();
        if (condExprValue) {
            this.visitSlist(slists[0])
        } else {
            //判断是否有else
            if (slists.length > 1) {
                this.visitSlist(slists[1])
            }
        }

        return 0
    }

    /**
     * Visit a parse tree produced by the `whileStatement`
     * labeled alternative in `PieParser.statement`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitWhileStatement(ctx: WhileStatementContext) {
        let condExpr = ctx.expr();
        let slist = ctx.slist();

        while (this.visitExpr(condExpr)) {
            this.visitSlist(slist);
        }

        return 0
    }

    /**
     * Visit a parse tree produced by the `callStatement`
     * labeled alternative in `PieParser.statement`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitCallStatement(ctx: CallStatementContext) {
        return this.visitCall(ctx.call());
    }

    /**
     * Visit a parse tree produced by the `emptyStatement`
     * labeled alternative in `PieParser.statement`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitEmptyStatement(ctx: EmptyStatementContext) {
        // 空语句不处理
        return 0
    }

    /**
     * Visit a parse tree produced by the `eqExpr`
     * labeled alternative in `PieParser.expr`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitEqExpr(ctx: EqExprContext) {
        let exprs = ctx.addexpr()
        let leftValue = this.visitAddexpr(exprs[0])
        if (exprs.length == 1) {
            return leftValue
        } else if (exprs.length == 2) {
            let rightValue = this.visitAddexpr(exprs[1]);
            return leftValue == rightValue;
        }
        return 0
    }

    /**
     * Visit a parse tree produced by the `ltExpr`
     * labeled alternative in `PieParser.expr`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitLtExpr(ctx: LtExprContext) {
        let exprs = ctx.addexpr()
        let leftValue = this.visitAddexpr(exprs[0])
        if (exprs.length == 1) {
            return leftValue
        } else if (exprs.length == 2) {
            let rightValue = this.visitAddexpr(exprs[1]);
            return leftValue < rightValue;
        }
        return 0
    }

    /**
     * Visit a parse tree produced by `PieParser.program`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitProgram(ctx: ProgramContext) {
        let statementS = ctx.statement();
        if (statementS.length > 0) {
            // 遍历求值
            statementS.forEach(s => {
                this.visitStatement(s)
            })
        }
        return 0
    }

    /**
     * Visit a parse tree produced by `PieParser.atom`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitAtom(ctx: AtomContext) {
        if (ctx.CHAR() != undefined) {
            return ctx.CHAR()?.text as string;
        } else if (ctx.INT()) {
            return parseInt(ctx.INT()?.text as string);
        } else if (ctx.FLOAT()) {
            return parseFloat(ctx.FLOAT()?.text as string);
        } else if (ctx.STRING()) {
            return parseInt(ctx.STRING()?.text as string);
        }
        else if (ctx.qid()) {
            //查找变量值
            return this.visitQid(ctx.qid() as QidContext)
        }
        else if (ctx.call()) {
            // 调用函数值
            return this.visitCall(ctx.call() as CallContext)
        }
        else if (ctx.instance()) {
            // 结构体设定默认值null
            return this.visitInstance(ctx.instance() as InstanceContext)
        }
        // else if (ctx.expr()) {
        //     // 求值表达式
        //     return this.visitExpr(ctx.expr() as ExprContext)
        // }
        return 0
    }

    /**
     * Visit a parse tree produced by `PieParser.mulexpr`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitMulexpr(ctx: MulexprContext) {
        let childExpr = ctx.atom();
        if (childExpr.length == 1) {
            // 单个表达式
            let leftValue = this.visitAtom(childExpr[0]);
            return leftValue;
        } else if (childExpr.length > 1) {
            // 多个连乘
            let result = 1;
            childExpr.forEach(c => {
                let tempV = this.visitAtom(c);
                if (isNumber(tempV)) {
                    result = result * (tempV as number)
                } else {
                    console.log("add", tempV)
                    throw new Error("add error")
                }
            })
            return result;
        }
        return -1
    }

    /**
     * Visit a parse tree produced by `PieParser.addexpr`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitAddexpr(ctx: AddexprContext) {
        if (ctx instanceof AddExprContext) {
            return this.visitAddExpr(ctx)
        } else if (ctx instanceof SubExprContext) {
            return this.visitSubExpr(ctx)
        }
        return 0
    }

    /**
     * Visit a parse tree produced by `PieParser.expr`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitExpr(ctx: ExprContext) {
        if (ctx instanceof EqExprContext) {
            return this.visitEqExpr(ctx)
        } else if (ctx instanceof LtExprContext) {
            return this.visitLtExpr(ctx)
        }
        return 0
    }

    /**
     * Visit a parse tree produced by `PieParser.statement`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitStatement(ctx: StatementContext) {
        if (ctx instanceof StructDefStatementContext) {
            return this.visitStructDefStatement(ctx);
        } else if (ctx instanceof AssignStatementContext) {
            return this.visitAssignStatement(ctx);
        } else if (ctx instanceof ReturnStatementContext) {
            return this.visitReturnStatement(ctx);
        } else if (ctx instanceof PrintStatementContext) {
            return this.visitPrintStatement(ctx);
        } else if (ctx instanceof IfStatementContext) {
            return this.visitIfStatement(ctx);
        } else if (ctx instanceof WhileStatementContext) {
            return this.visitWhileStatement(ctx);
        } else if (ctx instanceof CallStatementContext) {
            return this.visitCallStatement(ctx);
        } else if (ctx instanceof EmptyStatementContext) {

        }
        return 0
    }

    /**
     * Visit a parse tree produced by `PieParser.slist`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitSlist(ctx: SlistContext) {
        let stats = ctx.statement();
        let result = -1;
        stats.forEach(state => {
            result = this.visitStatement(state);
        })
        return result
    }

    /**
     * Visit a parse tree produced by `PieParser.structDefinition`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitStructDefinition(ctx: StructDefinitionContext) {
        // 结构体定义 求值器不处理
        return 0
    }

    /**
     * Visit a parse tree produced by `PieParser.vardef`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitVardef(ctx: VardefContext) {
        // 结构体字段和参数定义 求值器不处理
        return 0
    }

    /**
     * Visit a parse tree produced by `PieParser.instance`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitInstance(ctx: InstanceContext) {
        // 实例化对象 不做处理 字段默认值
        let structDef = this.currentScope?.resolve(ctx.ID().text);
        if(structDef == null){
            console.log("visitInstance",structDef)
            throw new Error("visitInstance error")
        }
        return "struc_"+structDef.name
    }

    /**
     * Visit a parse tree produced by `PieParser.qid`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitQid(ctx: QidContext) {
        // 查找变量值
        if (ctx instanceof SimpleVarContext) {
            return this.visitSimpleVar(ctx)
        } else if (ctx instanceof FieldVarContext) {
            return this.visitFieldVar(ctx)
        }
        return 0
    }

    /**
     * Visit a parse tree produced by `PieParser.functionDefinition`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitFunctionDefinition(ctx: FunctionDefinitionContext) {
        // 函数定义不做处理
        return 0
    }

    /**
     * Visit a parse tree produced by `PieParser.call`.
     * @param ctx the parse tree
     * @return the visitor result
     */
    visitCall(ctx: CallContext) {
        let funcName = ctx.ID();
        let args = ctx.expr();

        // 查找函数名称
        let funDef = this.currentScope?.resolve(funcName.text);
        if (funDef == null) {
            console.log("funDef not found", funcName.text)
            throw new Error("funcDef error")
        }
        // 检查slist
        if ((funDef as FunctionSymbol).slist == null) {
            console.log("funDef not found", funDef)
            throw new Error("funcDef slit error")
        }

        // 计算参数值
        let argsValue: any[] = [];
        args.forEach(a => {
            argsValue.push(
                this.visitExpr(a)
            )
        });
        // 设置参数的值 并调用
        (funDef as FunctionSymbol).setArgs(argsValue);

        if ((funDef as FunctionSymbol).slist != null) {
            // 记录当前函数作用域
            (this.currentScope as Scope) = funDef as FunctionSymbol;
            // 函数调用栈
            this.funcStack.push(funDef as FunctionSymbol);
            
            return this.visitSlist((funDef as FunctionSymbol).slist)
        } else {
            console.log("fun slit", funDef)
            throw new Error("func slit error")
        }
    }

}

const pieEval = new EvalVisitor(listener.symTab);
pieEval.visit(tree);